package com.xjrsoft.module.interfaceManager.controller;


import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.xjrsoft.common.Enum.DeleteMarkEnum;
import com.xjrsoft.common.Enum.EnabledMarkEnum;
import com.xjrsoft.common.page.ConventPage;
import com.xjrsoft.common.page.PageOutput;
import com.xjrsoft.common.result.Response;
import com.xjrsoft.core.tool.node.ForestNodeMerger;
import com.xjrsoft.core.tool.node.INode;
import com.xjrsoft.core.tool.utils.BeanUtil;
import com.xjrsoft.core.tool.utils.CollectionUtil;
import com.xjrsoft.core.tool.utils.StringUtil;
import com.xjrsoft.module.interfaceManager.constant.SchemaConst;
import com.xjrsoft.module.interfaceManager.dto.*;
import com.xjrsoft.module.interfaceManager.entity.*;
import com.xjrsoft.module.interfaceManager.service.*;
import com.xjrsoft.module.interfaceManager.utils.InterfaceUtil;
import com.xjrsoft.module.interfaceManager.vo.*;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiOperation;
import lombok.AllArgsConstructor;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import java.sql.SQLException;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 接口信息管理（框架内部接口） 前端控制器
 * </p>
 *
 * @author tzx
 * @since 2022-01-18
 */
@AllArgsConstructor
@RestController
@RequestMapping("/xjr-interface-info")
@Api(value = "/xjr-interface-info", tags = "接口管理信息")
public class XjrInterfaceInfoController {

    private IXjrInterfaceInfoService infoService;
    private IXjrInterfaceParamsService paramsService;
    private IXjrInterfaceSchemaService schemaService;
    private IXjrInterfaceOutputService outputService;
    private IXjrInterfaceCategoryService categoryService;


    @GetMapping("/{id}")
    @ApiOperation(value="获取接口管理详情")
    @ApiImplicitParam(name = "id",value = "id",required = true,dataType = "string")
    public Response<InfoVo> getById(@PathVariable String id){
        XjrInterfaceInfo info = infoService.getById(id);
        if(info==null){
            return Response.notOk("接口已删除!!!!");
        }
        if(info.getIsCustomize() == 0){
            InfoVo vo = BeanUtil.copy(info,InfoVo.class);
            List<XjrInterfaceParams> paramsList = paramsService.list(Wrappers.<XjrInterfaceParams>query().lambda().eq(XjrInterfaceParams::getInfoId, id).orderByAsc(XjrInterfaceParams::getSortCode));

            if(paramsList!=null && paramsList.size() > 0){
                List<ParamVo> paramVos = BeanUtil.copyList(paramsList, ParamVo.class);
                vo.setParams(paramVos);
            }

            List<XjrInterfaceOutput> outputList = outputService.list(Wrappers.<XjrInterfaceOutput>query().lambda().eq(XjrInterfaceOutput::getInfoId, id).orderByAsc(XjrInterfaceOutput::getSortCode));
            if(outputList!=null && outputList.size() > 0){
                List<OutputVo> outputVos = BeanUtil.copyList(outputList, OutputVo.class);
                vo.setOutputs(outputVos);
            }
            return Response.ok(vo);
        }
        else {
            InfoVo vo = BeanUtil.copy(info,InfoVo.class);
            XjrInterfaceSchema schema = schemaService.getOne(Wrappers.<XjrInterfaceSchema>query().lambda().eq(XjrInterfaceSchema::getInfoId, id));

            String schemaString = Optional.ofNullable(schema.getJsonSchema()).orElse("");

            if(StringUtil.isEmpty(schemaString)){
                return Response.notOk("当前接口配置错误！");
            }

            JSONObject allObj = JSONObject.parseObject(schemaString);

            JSONArray inputArray = allObj.getJSONArray(SchemaConst.INPUT_SETTING);

            List<ParamVo> paramVos = new ArrayList<>();
            for (int i = 0; i < inputArray.size(); i++) {
                JSONObject inputObj = inputArray.getJSONObject(i);
                if (!inputObj.getBoolean(SchemaConst.PARAM_ISCHECKED)){
                    continue;
                }
                ParamVo paramVo = new ParamVo();
                paramVo.setInfoId(id);
                paramVo.setParamKey(inputObj.getString(SchemaConst.PARAM_KEY));
                paramVo.setParamValue(inputObj.getString(SchemaConst.PARAM_VALUE));
                paramVo.setType(inputObj.getInteger(SchemaConst.PARAM_TYPE));
                paramVo.setDescription(inputObj.getString(SchemaConst.PARAM_DES));
                paramVo.setChecked(inputObj.getBoolean(SchemaConst.PARAM_ISCHECKED));
                paramVos.add(paramVo);
            }

            JSONArray outputArray = allObj.getJSONArray(SchemaConst.OUTPUT_SETTING);
            List<OutputVo> outputVos = new ArrayList<>();
            for (int i = 0; i < outputArray.size(); i++) {
                JSONObject outputObj = outputArray.getJSONObject(i);


                if (!outputObj.getBoolean(SchemaConst.OUTPUT_ISCHECKED)){
                    continue;
                }

                OutputVo outputVo = new OutputVo();
                outputVo.setInfoId(id);
                outputVo.setOutputKey(outputObj.getString(SchemaConst.OUTPUT_CODE));
                outputVo.setResultKey(outputObj.getString(SchemaConst.OUTPUT_RESULTKEY));

                if(outputObj.getInteger(SchemaConst.OUTPUT_VALTYPE) == 1){
                    JSONObject saveCodeObj = outputObj.getJSONObject(SchemaConst.OUTPUT_SAVECODE);
                    outputVo.setSettingJson(saveCodeObj.toJSONString());
//                    if (saveCodeObj != null && !saveCodeObj.isEmpty()) {
//                        JSONArray objJSONArray = saveCodeObj.getJSONArray(SchemaConst.OUTPUT_OBJVARIABLE);
//
//                        outputVo.setSettingJson(objJSONArray.toJSONString());
//
//                    }
                }

                outputVo.setType(outputObj.getInteger(SchemaConst.OUTPUT_VALTYPE));
//                outputVo.setOutputValType(outputObj.getInteger(SchemaConst.OUTPUT_VALTYPE));

                outputVos.add(outputVo);
            }

            vo.setParams(paramVos);
            vo.setOutputs(outputVos);
            return Response.ok(vo);
        }

    }

    @GetMapping("/customize/{id}")
    @ApiOperation(value="获取自定义接口管理详情")
    @ApiImplicitParam(name = "id",value = "id",required = true,dataType = "string")
    public Response<CustomizeInfoVo> getCustomizeById(@PathVariable String id){
        XjrInterfaceInfo info = infoService.getById(id);

        if(info == null || info.getIsCustomize() == 0){
            return Response.notOk("当前接口不属于自定义接口！");
        }

        XjrInterfaceSchema schema = schemaService.getOne(Wrappers.<XjrInterfaceSchema>query().lambda().eq(XjrInterfaceSchema::getInfoId, id));

        CustomizeInfoVo vo = BeanUtil.copy(info, CustomizeInfoVo.class);

        vo.setJsonSchema(schema.getJsonSchema());

        return Response.ok(vo);
    }

    @GetMapping("/system/{id}")
    @ApiOperation(value="获取系统接口管理详情")
    @ApiImplicitParam(name = "id",value = "id",required = true,dataType = "string")
    public Response<InfoVo> getSystemById(@PathVariable String id){
        XjrInterfaceInfo info = infoService.getById(id);

        if(info == null || info.getIsCustomize() == 1){
            return Response.notOk("当前接口不属于系统接口！");
        }


        InfoVo vo = BeanUtil.copy(info,InfoVo.class);
        List<XjrInterfaceParams> paramsList = paramsService.list(Wrappers.<XjrInterfaceParams>query().lambda().eq(XjrInterfaceParams::getInfoId, id));

        if(paramsList!=null && paramsList.size() > 0){
            List<ParamVo> paramVos = BeanUtil.copyList(paramsList, ParamVo.class);
            vo.setParams(paramVos);
        }

        List<XjrInterfaceOutput> outputList = outputService.list(Wrappers.<XjrInterfaceOutput>query().lambda().eq(XjrInterfaceOutput::getInfoId, id));
        if(outputList!=null && outputList.size() > 0){
            List<OutputVo> outputVos = BeanUtil.copyList(outputList, OutputVo.class);
            vo.setOutputs(outputVos);
        }


        return Response.ok(vo);
    }

    @GetMapping("/list")
    @ApiOperation(value="获取接口管理列表")
    public Response<PageOutput<InfoListVo>> list(InfoListDto dto){
        IPage<XjrInterfaceInfo> page = infoService.page(ConventPage.getPage(dto), Wrappers.<XjrInterfaceInfo>query().lambda()
                .eq(XjrInterfaceInfo::getDeleteMark, DeleteMarkEnum.NODELETE.getCode())
//                .eq(XjrInterfaceInfo::getEnabledMark,EnabledMarkEnum.ENABLED.getCode())
                .eq(XjrInterfaceInfo::getIsCustomize,0)
                .eq(StringUtil.isNotBlank(dto.getCategory()),XjrInterfaceInfo::getCategoryId,dto.getCategory())
                .eq(dto.getMethod() != null,XjrInterfaceInfo::getRequestMethod,dto.getMethod())
                .like(StringUtil.isNotBlank(dto.getKeyword()), XjrInterfaceInfo::getName, dto.getKeyword()).or()
                .like(StringUtil.isNotBlank(dto.getKeyword()), XjrInterfaceInfo::getUrlAddress, dto.getKeyword())
                .orderByDesc(XjrInterfaceInfo::getCreateDate));

        if(page.getRecords().size() == 0){
            return Response.ok(ConventPage.getPageOutput(page, InfoListVo.class));
        }
        List<String> ids = page.getRecords().stream().map(XjrInterfaceInfo::getCategoryId).collect(Collectors.toList());
        List<XjrInterfaceCategory> list = categoryService.list(Wrappers.<XjrInterfaceCategory>query().lambda().in(XjrInterfaceCategory::getId, ids));
        PageOutput<InfoListVo> pageOutput = ConventPage.getPageOutput(page, InfoListVo.class);

        for (InfoListVo row : pageOutput.getRows()) {
            Optional<XjrInterfaceCategory> category = list.stream().filter(x -> StringUtil.equals(x.getId(), row.getCategoryId())).findFirst();

            category.ifPresent(xjrInterfaceCategory -> row.setCategoryName(xjrInterfaceCategory.getName()));
        }
        return Response.ok(pageOutput);
    }

    @GetMapping("/customize/list")
    @ApiOperation(value="获取自定义接口管理列表")
    public Response<PageOutput<InfoListVo>> customizeList(InfoListDto dto){

        IPage<XjrInterfaceInfo> page = infoService.page(ConventPage.getPage(dto), Wrappers.<XjrInterfaceInfo>query().lambda()
                .eq(XjrInterfaceInfo::getDeleteMark, DeleteMarkEnum.NODELETE.getCode())
//                .eq(XjrInterfaceInfo::getEnabledMark,EnabledMarkEnum.ENABLED.getCode())
                .eq(XjrInterfaceInfo::getIsCustomize,1)
                .eq(StringUtil.isNotBlank(dto.getCategory()),XjrInterfaceInfo::getCategoryId,dto.getCategory())
                .eq(dto.getMethod() != null,XjrInterfaceInfo::getRequestMethod,dto.getMethod())
                .like(StringUtil.isNotBlank(dto.getKeyword()), XjrInterfaceInfo::getName, dto.getKeyword()).or()
                .like(StringUtil.isNotBlank(dto.getKeyword()), XjrInterfaceInfo::getUrlAddress, dto.getKeyword())
                .orderByDesc(XjrInterfaceInfo::getCreateDate));

        if(page.getRecords().size() == 0){
            return Response.ok(ConventPage.getPageOutput(page, InfoListVo.class));
        }

        List<String> ids = page.getRecords().stream().map(XjrInterfaceInfo::getCategoryId).collect(Collectors.toList());
        List<XjrInterfaceCategory> list = categoryService.list(Wrappers.<XjrInterfaceCategory>query().lambda().in(XjrInterfaceCategory::getId, ids));
        PageOutput<InfoListVo> pageOutput = ConventPage.getPageOutput(page, InfoListVo.class);

        for (InfoListVo row : pageOutput.getRows()) {
            Optional<XjrInterfaceCategory> category = list.stream().filter(x -> StringUtil.equals(x.getId(), row.getCategoryId())).findFirst();

            category.ifPresent(xjrInterfaceCategory -> row.setCategoryName(xjrInterfaceCategory.getName()));
        }

        return Response.ok(pageOutput);
    }

    @PostMapping
    @ApiOperation(value="新增接口管理")
    @Transactional
    public Response<Boolean> add(@RequestBody AddInfoDto dto){
        return Response.status(infoService.add(dto));
    }

    @GetMapping("/list/all")
    @ApiOperation(value="获取系统接口 以及 自定义接口")
    public Response<PageOutput<InfoListVo>> allList(InfoListDto dto){
        IPage<XjrInterfaceInfo> page = infoService.page(ConventPage.getPage(dto), Wrappers.<XjrInterfaceInfo>query().lambda()
                .eq(XjrInterfaceInfo::getDeleteMark, DeleteMarkEnum.NODELETE.getCode())
                .eq(XjrInterfaceInfo::getEnabledMark,EnabledMarkEnum.ENABLED.getCode())
                .eq(StringUtil.isNotBlank(dto.getCategory()),XjrInterfaceInfo::getCategoryId,dto.getCategory())
                .eq(dto.getMethod() != null,XjrInterfaceInfo::getRequestMethod,dto.getMethod())
                .like(StringUtil.isNotBlank(dto.getKeyword()), XjrInterfaceInfo::getName, dto.getKeyword()).or()
                .like(StringUtil.isNotBlank(dto.getKeyword()), XjrInterfaceInfo::getUrlAddress, dto.getKeyword()).orderByDesc(XjrInterfaceInfo::getCreateDate));

        if(page.getRecords().size() == 0){
            return Response.ok(ConventPage.getPageOutput(page, InfoListVo.class));
        }
        List<String> ids = page.getRecords().stream().map(XjrInterfaceInfo::getCategoryId).collect(Collectors.toList());
        List<XjrInterfaceCategory> list = categoryService.list(Wrappers.<XjrInterfaceCategory>query().lambda().in(XjrInterfaceCategory::getId, ids));
        PageOutput<InfoListVo> pageOutput = ConventPage.getPageOutput(page, InfoListVo.class);

        for (InfoListVo row : pageOutput.getRows()) {
            Optional<XjrInterfaceCategory> category = list.stream().filter(x -> StringUtil.equals(x.getId(), row.getCategoryId())).findFirst();

            category.ifPresent(xjrInterfaceCategory -> row.setCategoryName(xjrInterfaceCategory.getName()));
        }
        return Response.ok(pageOutput);
    }

    @GetMapping("/tree-list")
    @ApiOperation(value="获取系统接口 以及 自定义接口的接口分类树")
    public Response<List<CategoryTreeVo>> allTreeList(@RequestParam(value = "keyword", required = false) String keyword) {
        List<XjrInterfaceCategory> categoryList = categoryService.list(Wrappers.<XjrInterfaceCategory>query().lambda()
                .eq(XjrInterfaceCategory::getEnabledMark, 1)
                .orderByAsc(XjrInterfaceCategory::getSortCode));
        List<CategoryTreeVo> categoryTreeVoList = BeanUtil.copyList(categoryList, CategoryTreeVo.class);
        List<CategoryTreeVo> resultList = ForestNodeMerger.merge(categoryTreeVoList);
        List<XjrInterfaceInfo> interfaceInfoList = infoService.list(Wrappers.<XjrInterfaceInfo>query().lambda()
                .eq(XjrInterfaceInfo::getEnabledMark, 1)
                .and(!StringUtil.isEmpty(keyword), subWrapper -> subWrapper.like(XjrInterfaceInfo::getName, keyword).or().like(XjrInterfaceInfo::getUrlAddress, keyword))
                .orderByDesc(XjrInterfaceInfo::getCreateDate));
        List<InfoTreeListVo> infoListVoList = BeanUtil.copyList(interfaceInfoList, InfoTreeListVo.class);
        for (CategoryTreeVo categoryTreeVo : categoryTreeVoList) {
            String id = categoryTreeVo.getId();
            for (InfoTreeListVo infoListVo : infoListVoList) {
                if (StringUtil.equals(id, infoListVo.getCategoryId())) {
                    infoListVo.setParentId(id);
                    categoryTreeVo.getChildren().add(infoListVo);
                }
            }
        }
        // 构建返回数据
        Set<String> categoryIdList = InterfaceUtil.getResultCategoryIdList(resultList);
        List<CategoryTreeVo> resultVoList = new ArrayList<>();
        for (CategoryTreeVo categoryTreeVo : categoryTreeVoList) {
            if (categoryIdList.contains(categoryTreeVo.getId())) {
                resultVoList.add(categoryTreeVo);
            }
            List<INode> children = categoryTreeVo.getChildren();
            if (CollectionUtil.isNotEmpty(children) && !(children.get(0) instanceof InfoTreeListVo)) {
                children.clear();
            }
        }
        return Response.ok(ForestNodeMerger.merge(resultVoList));
    }

    @PostMapping("/customize")
    @ApiOperation(value="新增自定义接口管理")
    @Transactional
    public Response<Boolean> addCustomize(@RequestBody AddCustomizeInfoDto dto){
        int count = infoService.count(Wrappers.<XjrInterfaceInfo>query().lambda().eq(XjrInterfaceInfo::getName, dto.getName()));

        if(count > 0){
            return Response.notOk("已存在相同名称的接口！");
        }
        XjrInterfaceInfo info = BeanUtil.copy(dto, XjrInterfaceInfo.class);

        boolean success = infoService.save(info);
        if(success){
            //如果不是自定义接口
            XjrInterfaceSchema schema = new XjrInterfaceSchema();
            schema.setInfoId(info.getId());
            JSONObject jsonObj = new JSONObject(dto.getSettings());
            schema.setJsonSchema(jsonObj.toString());
            return Response.ok(schemaService.save(schema));
        }
        else {
            return Response.notOk("新增自定义接口管理错误！");
        }
    }

    @PutMapping("/{id}/system")
    @ApiOperation(value="修改系统接口")
    @Transactional
    public Response<Boolean> updateSystem(@PathVariable String id, @RequestBody AddInfoDto dto){

        int count = infoService.count(Wrappers.<XjrInterfaceInfo>query().lambda().eq(XjrInterfaceInfo::getName, dto.getName()).ne(XjrInterfaceInfo::getId,id));

        if(count > 0){
            return Response.notOk("已存在相同名称的接口！");
        }
        XjrInterfaceInfo info = BeanUtil.copy(dto, XjrInterfaceInfo.class);
        info.setId(id);
        boolean success = infoService.updateById(info);
        if(success){
            //先删除原有的
            paramsService.remove(Wrappers.<XjrInterfaceParams>query().lambda().eq(XjrInterfaceParams::getInfoId,id));
            outputService.remove(Wrappers.<XjrInterfaceOutput>query().lambda().eq(XjrInterfaceOutput::getInfoId,id));

            //如果不是自定义接口
            List<AddParamDto> params = Optional.ofNullable(dto.getParams()).orElse(new ArrayList<>());
            List<AddOutputDto> outputs = Optional.ofNullable(dto.getOutputs()).orElse(new ArrayList<>());

            if(params.size() > 0){
                List<XjrInterfaceParams> paramsList = BeanUtil.copyList(params,XjrInterfaceParams.class);

                for (XjrInterfaceParams param : paramsList) {
                    param.setInfoId(info.getId());
                }
                paramsService.saveBatch(paramsList);
            }

            if(outputs.size() > 0){
                List<XjrInterfaceOutput> outputList = BeanUtil.copyList(outputs,XjrInterfaceOutput.class);

                for (XjrInterfaceOutput output : outputList) {
                    output.setInfoId(info.getId());
                }
                outputService.saveBatch(outputList);
            }
            return Response.ok(true);
        }
        else {
            return Response.notOk("新增接口管理信息错误！");
        }
    }

    @PutMapping("/{id}/customize")
    @ApiOperation(value="修改自定义接口")
    @Transactional
    public Response<Boolean> updateCustomize(@PathVariable String id, @RequestBody AddCustomizeInfoDto dto){
        int count = infoService.count(Wrappers.<XjrInterfaceInfo>query().lambda().eq(XjrInterfaceInfo::getName, dto.getName()).ne(XjrInterfaceInfo::getId,id));

        if(count > 0){
            return Response.notOk("已存在相同名称的接口！");
        }
        XjrInterfaceInfo info = BeanUtil.copy(dto, XjrInterfaceInfo.class);
        info.setId(id);
        boolean success = infoService.updateById(info);
        if(success){
            //如果不是自定义接口
            XjrInterfaceSchema schema = schemaService.getOne(Wrappers.<XjrInterfaceSchema>query().lambda().eq(XjrInterfaceSchema::getInfoId, id));

            if(schema==null){
                return Response.notOk("修改自定义接口管理错误！");
            }
            JSONObject jsonObj = new JSONObject(dto.getSettings());
            schema.setJsonSchema(jsonObj.toString());
            return Response.ok(schemaService.updateById(schema));
        }
        else {
            return Response.notOk("修改自定义接口管理错误！");
        }
    }

    @PutMapping("/{id}/enabled")
    @ApiOperation(value="启用接口")
    public Response<Boolean> enabled(@PathVariable String id){
        XjrInterfaceInfo info = new XjrInterfaceInfo();
        info.setId(id);
        info.setEnabledMark(EnabledMarkEnum.ENABLED.getCode());
        return Response.ok(infoService.updateById(info));
    }

    @PutMapping("/{id}/disabled")
    @ApiOperation(value="禁用接口")
    public Response<Boolean> disabled(@PathVariable String id){
        XjrInterfaceInfo info = new XjrInterfaceInfo();
        info.setId(id);
        info.setEnabledMark(EnabledMarkEnum.NOENABLED.getCode());
        return Response.ok(infoService.updateById(info));
    }

    @DeleteMapping("/{ids}")
    @ApiOperation(value="删除及批量删除")
    public Response<Boolean> delete(@PathVariable String ids){
        List<String> idList = Arrays.asList(ids.split(","));
        if (infoService.removeByIds(idList)) {
            //先删除原有的
            paramsService.remove(Wrappers.<XjrInterfaceParams>query().lambda().in(XjrInterfaceParams::getInfoId,idList));
            outputService.remove(Wrappers.<XjrInterfaceOutput>query().lambda().in(XjrInterfaceOutput::getInfoId,idList));
            return Response.ok(true);
        }
        else {
            return Response.notOk("删除接口管理信息错误！");
        }
    }

    @PostMapping("/execute/{id}")
    public Response execute(@PathVariable String id, @RequestBody Map<String, String> paramMap, HttpServletRequest request) throws SQLException {
        // 参数转换
        Enumeration<String> parameterNames = request.getParameterNames();
        while (parameterNames.hasMoreElements()) {
            String name = parameterNames.nextElement();
            paramMap.put(name, request.getParameter(name));
        }
        return infoService.execute(id,  paramMap,request);
    }
}
